﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using HYCodeBase.Math;
using HYRevitCode.RevitTopologySuite;
using HYRevitCode.TransformUtility;
using HYRevitCode.XYZUtility;

namespace HYRevitCode.FaceCalculateUtility
{
	public class PlanarFacePacker
	{
		internal Transform UseTransformToXoY
		{
			get
			{
				return this.m_useTransformToXoY;
			}
			private set
			{
				this.m_useTransformToXoY = value;
			}
		}

		internal Dictionary<PlanarFacePacker, bool> LinkFace
		{
			get
			{
				return this.m_LinkFace;
			}
			private set
			{
				this.m_LinkFace = value;
			}
		}

		internal bool IfNearBoundary
		{
			get
			{
				return this.m_IfNearBoundary;
			}
			set
			{
				this.m_IfNearBoundary = value;
			}
		}

		internal PlanarFacePacker OrigionPacker
		{
			get
			{
				return this.m_OrigionPacker;
			}
			private set
			{
				this.m_OrigionPacker = value;
			}
		}

		internal List<XYZ> LstFaceBoundaryPoint
		{
			get
			{
				return this.m_LstFaceBoundaryPoint;
			}
			private set
			{
				this.m_LstFaceBoundaryPoint = value;
			}
		}

		public PlanarFace ThisFace
		{
			get
			{
				return this.m_thisFace;
			}
			private set
			{
				this.m_thisFace = value;
			}
		}

		public List<RevitPolygonDataBean> ThisPolygon
		{
			get
			{
				return this.m_lstThisPolygon;
			}
			private set
			{
				this.m_lstThisPolygon = value;
			}
		}

		public BasePacker ThisBasePacker
		{
			get
			{
				return this.m_thisBasePacker;
			}
			set
			{
				this.m_thisBasePacker = value;
			}
		}

		public double EffectArea
		{
			get
			{
				return this.m_dEffectArea;
			}
			private set
			{
				this.m_dEffectArea = value;
			}
		}

		internal PlanarFacePacker(PlanarFace inputFace, BasePacker inputElementPacker)
		{
			this.ThisFace = inputFace;
			this.ThisBasePacker = inputElementPacker;
			this.LstFaceBoundaryPoint = GeometryHelper.GetBoundaryPoint(this.ThisFace);
			this.UseTransformToXoY = TransformUtilityMethod.CalculateTransformFromPlanarFaceToXoY(this.ThisFace);
			List<CurveLoop> list = inputFace.GetEdgesAsCurveLoops().ToList<CurveLoop>();
			CurveLoop curveLoop = list.First<CurveLoop>();
			list.Remove(curveLoop);
			curveLoop = this.GetTransformCurveLoop(curveLoop, this.UseTransformToXoY);
			List<CurveLoop> list2 = new List<CurveLoop>();
			if (list.Count != 0)
			{
				using (List<CurveLoop>.Enumerator enumerator = list.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						CurveLoop useCurveLoop = enumerator.Current;
						CurveLoop transformCurveLoop = this.GetTransformCurveLoop(useCurveLoop, this.UseTransformToXoY);
						list2.Add(transformCurveLoop);
					}
					goto IL_C9;
				}
			}
			list2 = null;
			IL_C9:
			RevitPolygonDataBean revitPolygonDataBean = new RevitPolygonDataBean(curveLoop, list2, 3);
			this.ThisPolygon = new List<RevitPolygonDataBean>
			{
				revitPolygonDataBean
			};
			this.EffectArea = ((revitPolygonDataBean.Area != null) ? revitPolygonDataBean.Area.Value : 0.0);
		}

		internal PlanarFacePacker(PlanarFacePacker inputOrigion)
		{
			this.m_OrigionPacker = inputOrigion;
			inputOrigion.m_lstShadowPackers.Add(this);
			this.ThisFace = inputOrigion.ThisFace;
			this.ThisBasePacker = inputOrigion.ThisBasePacker;
			this.LstFaceBoundaryPoint = GeometryHelper.GetBoundaryPoint(this.ThisFace);
			this.UseTransformToXoY = TransformUtilityMethod.CalculateTransformFromPlanarFaceToXoY(this.ThisFace);
			List<CurveLoop> list = this.ThisFace.GetEdgesAsCurveLoops().ToList<CurveLoop>();
			CurveLoop curveLoop = list.First<CurveLoop>();
			list.Remove(curveLoop);
			curveLoop = this.GetTransformCurveLoop(curveLoop, this.UseTransformToXoY);
			List<CurveLoop> list2 = new List<CurveLoop>();
			foreach (CurveLoop useCurveLoop in list)
			{
				CurveLoop transformCurveLoop = this.GetTransformCurveLoop(useCurveLoop, this.UseTransformToXoY);
				list2.Add(transformCurveLoop);
			}
			RevitPolygonDataBean revitPolygonDataBean = new RevitPolygonDataBean(curveLoop, list2, 3);
			this.ThisPolygon = new List<RevitPolygonDataBean>
			{
				revitPolygonDataBean
			};
			this.EffectArea = ((revitPolygonDataBean.Area != null) ? revitPolygonDataBean.Area.Value : 0.0);
		}

		internal bool IfHasShadowPacker()
		{
			return this.m_lstShadowPackers.Count != 0;
		}

		internal bool IfInSplitBoxPacker(SplitBoxPacker inputBox)
		{
			bool flag = this.IfInSplitBoxPackerBaseMethod(inputBox);
			if (flag && this.IfNearInputBoundaryBaseMethod(inputBox))
			{
				this.m_IfNearBoundary = true;
			}
			return flag;
		}

		internal void UpdataShape()
		{
			for (int i = 0; i < this.LinkFace.Count; i++)
			{
				KeyValuePair<PlanarFacePacker, bool> keyValuePair = this.LinkFace.ElementAt(i);
				if (!keyValuePair.Value)
				{
					List<RevitPolygonDataBean> list = new List<RevitPolygonDataBean>();
					foreach (RevitPolygonDataBean inputOne in this.m_lstThisPolygon)
					{
						foreach (RevitPolygonDataBean inputTwo in keyValuePair.Key.m_lstThisPolygon)
						{
							List<RevitPolygonDataBean> intersectionPolygonNoneZ = PolygonUtility.GetIntersectionPolygonNoneZ(inputOne, inputTwo);
							if (intersectionPolygonNoneZ.Count != 0)
							{
								list.AddRange(intersectionPolygonNoneZ);
							}
						}
					}
					this.UpdataShape(keyValuePair.Key, list);
					keyValuePair.Key.UpdataShape(this, list);
				}
			}
		}

		internal void ReMergeShape()
		{
			double effectArea = this.EffectArea;
			if (this.IfHasShadowPacker())
			{
				foreach (PlanarFacePacker planarFacePacker in this.m_lstShadowPackers)
				{
					foreach (KeyValuePair<PlanarFacePacker, bool> keyValuePair in planarFacePacker.LinkFace)
					{
						PlanarFacePacker key = (keyValuePair.Key.OrigionPacker == null) ? keyValuePair.Key : keyValuePair.Key.OrigionPacker;
						if (!this.LinkFace.ContainsKey(key))
						{
							this.LinkFace.Add(key, false);
						}
					}
				}
				this.UpdataShape();
				double num = 0.0;
				for (int i = 0; i < this.ThisPolygon.Count; i++)
				{
					double num2 = (this.ThisPolygon[i].Area == null) ? 0.0 : this.ThisPolygon[i].Area.Value;
					num += num2;
				}
				this.EffectArea = num;
			}
		}

		internal void TryAddLinkePacker(PlanarFacePacker input)
		{
			if (input == null)
			{
				return;
			}
			if (!this.IfFaceLinkeThis(input))
			{
				return;
			}
			foreach (KeyValuePair<PlanarFacePacker, bool> keyValuePair in this.LinkFace)
			{
				if (keyValuePair.Key.OrigionPacker != null && keyValuePair.Key.OrigionPacker == input)
				{
					return;
				}
			}
			if (!this.LinkFace.ContainsKey(input))
			{
				this.LinkFace.Add(input, false);
			}
			if (!input.LinkFace.ContainsKey(this))
			{
				input.LinkFace.Add(this, false);
			}
		}

		private bool IfFaceLinkeThis(PlanarFacePacker input)
		{
			if (this.ThisFace.FaceNormal.IsAlmostEqualTo(-input.ThisFace.FaceNormal))
			{
				double towPlanarFaceDis = GeometryHelper.GetTowPlanarFaceDis(this.ThisFace, input.ThisFace);
				if (towPlanarFaceDis != -1.0 && MathUtility.Lessthan_Or_Equal(towPlanarFaceDis, 1E-10))
				{
					return true;
				}
			}
			return false;
		}

		private void UpdataShape(PlanarFacePacker input, List<RevitPolygonDataBean> inputIntersectionPolygons)
		{
			if (this.OrigionPacker != null)
			{
				this.LinkFace[input] = true;
				return;
			}
			List<RevitPolygonDataBean> list = new List<RevitPolygonDataBean>();
			for (int i = 0; i < this.m_lstThisPolygon.Count; i++)
			{
				foreach (RevitPolygonDataBean inputTwo in inputIntersectionPolygons)
				{
					List<RevitPolygonDataBean> differencePolygonNoneZ = PolygonUtility.GetDifferencePolygonNoneZ(this.m_lstThisPolygon[i], inputTwo);
					if (differencePolygonNoneZ.Count != 0)
					{
						list.AddRange(differencePolygonNoneZ);
					}
					else
					{
						list.Add(this.m_lstThisPolygon[i]);
					}
				}
			}
			if (list.Count != 0)
			{
				this.m_lstThisPolygon = list;
			}
			this.LinkFace[input] = true;
		}

		private bool IfInSplitBoxPackerBaseMethod(SplitBoxPacker inputBox)
		{
			XYZ boxCenterPoint = inputBox.MaxPoint.Add(inputBox.MinPoint).Divide(2.0);
			XYZ xyz = new XYZ();
			IntersectionResult intersectionResult = this.ThisFace.Project(boxCenterPoint);
			if (intersectionResult != null)
			{
				xyz = intersectionResult.XYZPoint;
			}
			else
			{
				List<XYZ> list = new List<XYZ>();
				foreach (CurveLoop source in this.ThisFace.GetEdgesAsCurveLoops().ToList<CurveLoop>())
				{
					foreach (Curve curve in source.ToList<Curve>())
					{
						XYZ xyzpoint = curve.Project(boxCenterPoint).XYZPoint;
						list.Add(xyzpoint);
					}
				}
				xyz = (from p in list
				orderby p.DistanceTo(boxCenterPoint)
				select p).ToList<XYZ>().First<XYZ>();
			}
			if (xyz == null)
			{
				return false;
			}
			bool flag = MathUtility.Greaterthan_Or_Equal(xyz.Z, inputBox.MinPoint.Z);
			bool flag2 = MathUtility.Lessthan_Or_Equal(xyz.Z, inputBox.MaxPoint.Z);
			if (!flag || !flag2)
			{
				return false;
			}
			bool flag3 = MathUtility.Greaterthan_Or_Equal(xyz.X, inputBox.MinPoint.X);
			bool flag4 = MathUtility.Lessthan_Or_Equal(xyz.X, inputBox.MaxPoint.X);
			if (!flag3 || !flag4)
			{
				return false;
			}
			bool flag5 = MathUtility.Greaterthan_Or_Equal(xyz.Y, inputBox.MinPoint.Y);
			bool flag6 = MathUtility.Lessthan_Or_Equal(xyz.Y, inputBox.MaxPoint.Y);
			return flag5 && flag6;
		}

		private bool IfNearInputBoundaryBaseMethod(SplitBoxPacker inputBox)
		{
			if (this.ThisFace.FaceNormal.IsAlmostEqualTo(XYZ.BasisZ) || this.ThisFace.FaceNormal.IsAlmostEqualTo(-XYZ.BasisZ))
			{
				List<XYZ> source = (from p in this.LstFaceBoundaryPoint
				orderby p.Z
				select p).ToList<XYZ>();
				bool flag = MathUtility.Lessthan_Or_Equal(Math.Abs(source.Last<XYZ>().Z - inputBox.MaxPoint.Z), 1E-10);
				return MathUtility.Lessthan_Or_Equal(Math.Abs(source.First<XYZ>().Z - inputBox.MinPoint.Z), 1E-10) || flag;
			}
			new List<XYZ>();
			foreach (XYZ point in this.LstFaceBoundaryPoint)
			{
				XYZ xyz = XYZUtilityMethod.TransformPoint(point, this.UseTransformToXoY);
				using (List<Line>.Enumerator enumerator2 = inputBox.LstBoundary.GetEnumerator())
				{
					while (enumerator2.MoveNext())
					{
						if (MathUtility.Lessthan_Or_Equal(Math.Abs(enumerator2.Current.Project(xyz).XYZPoint.DistanceTo(xyz)), 1E-10))
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		private CurveLoop GetTransformCurveLoop(CurveLoop useCurveLoop, Transform useTransform)
		{
			List<Curve> list = new List<Curve>();
			foreach (Curve curve in useCurveLoop)
			{
				Curve item = curve.CreateTransformed(useTransform);
				list.Add(item);
			}
			return CurveLoop.Create(list);
		}

		private PlanarFace m_thisFace;

		private List<RevitPolygonDataBean> m_lstThisPolygon;

		private Transform m_useTransformToXoY;

		private double m_dEffectArea;

		private List<XYZ> m_LstFaceBoundaryPoint;

		private Dictionary<PlanarFacePacker, bool> m_LinkFace = new Dictionary<PlanarFacePacker, bool>();

		private BasePacker m_thisBasePacker;

		private bool m_IfNearBoundary;

		private PlanarFacePacker m_OrigionPacker;

		private List<PlanarFacePacker> m_lstShadowPackers = new List<PlanarFacePacker>();

		private const double DNEARBOUNDARYTHRESHOLD = 1E-10;

		private const double FACELINKTHRESHOLD = 1E-10;
	}
}
